<template>
	<view class="background-container" :style="{ backgroundImage: `url(${bgImages.nursesStation})` }">
		<timeModule></timeModule>
		<view class="nurse-container">
			<image class="nurse_icon" :src="item.nurse" mode="aspectFill"></image>  
		</view>
		<view class="man_container">
			<image class="man_icon" :src="item.man" mode="aspectFill"></image>
		</view>
		<view class="next" @click="handleNext">
			<uni-icons type="right" color="#fff" size="50" ></uni-icons>
		</view>
		
		<!-- 体重秤 -->
		<view class="weighing-scale" @click="handleWeighing" :style="{ backgroundImage: `url(${uiImages.weight})` }"></view>
		<!-- 称重的人 -->
		<view class="people" v-if="showPeople"></view>
		
		<!-- 语音按钮 -->
		<view class="voice" @touchstart="touchStart" @touchend="touchEnd">
			<uni-icons class="voice-icon" :type="isRecording ? 'mic-filled' : 'mic'" color="#fff" size="45"></uni-icons>
		</view>

		<!-- 对话框 -->
		<view class="nurse_say" :style="{ width: getNurseSayWidth }">
			<text>
				{{ (heightResult && weightResult) ? `身高为 ${heightResult} cm，体重为 ${weightResult} kg` : (voiceResult || '您好，请问您叫什么名字？') }}
			</text>
		</view>
		<view class="man_say">
			<text>我叫陈广洪</text>
		</view>
	</view>

</template>

<script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue'
import {bgImages, uiImages } from '@/src/dataResource.js';

// 修正数据结构，合并为一个对象
const item = ref({ 
	nurse: 'https://i.postimg.cc/dV0kNTj9/1.png' ,
	man:'https://i.postimg.cc/5NYr70LX/avatar.png'
				})
const handleNext = () =>{
	
	uni.navigateTo({
		url:"/pages/corridor/corridor"
	})
} 

// 新增：控制称重人显示和称重结果
const showPeople = ref(false)
const weightResult = ref('')
const heightResult = ref('') // 新增身高

// 新增：称重事件
const handleWeighing = () => {
  showPeople.value = true
  // 生成身高和体重
  const weight = 50 + Math.floor(Math.random() * 30) // 50~79kg
  const height = 150 + Math.floor(Math.random() * 41) // 150~190cm
  weightResult.value = weight
  heightResult.value = height
}

// 语音识别相关变量（对齐 ward 页面实现：uniRecorder + uniCloud）
const voiceResult = ref('') // 语音识别结果
const isRecording = ref(false) // 是否正在录音
let recorderManager = null
let audioFilePath = null
let recorderBound = false // 防止重复绑定回调
let isUploading = false // 防止重复上传

// 根据文字长度计算对话框宽度
const getNurseSayWidth = computed(() => {
	const baseWidth = 250; // 基础宽度
	const textLength = 14; // 默认文字长度
	return `${baseWidth}rpx`;
});

const getManSayWidth = computed(() => {
	const baseWidth = 120; // 基础宽度
	const textLength = voiceResult.value ? voiceResult.value.length : 5; // 文字长度
	// 每个字符增加约20rpx宽度，最小宽度为baseWidth
	return `${Math.max(baseWidth, baseWidth + (textLength - 5) * 20)}rpx`;
});

// 录音初始化（同 ward 页面）
onMounted(() => {
    try {
        recorderManager = uni.getRecorderManager()
        if (!recorderManager) {
            console.error('录音管理器初始化失败')
            return
        }
        // 防重复绑定
        if (recorderBound) return
        recorderBound = true
        // 录音开始
        recorderManager.onStart(() => {
            isRecording.value = true
            voiceResult.value = '正在聆听...'
        })
        // 录音结束
        recorderManager.onStop((res) => {
            isRecording.value = false
            if (isUploading) return
            audioFilePath = res.tempFilePath
            if (audioFilePath) {
                isUploading = true
                ;(async () => {
                    try {
                        await uploadToUniCloud(audioFilePath)
                    } finally {
                        isUploading = false
                    }
                })()
            } else {
                voiceResult.value = '录音文件生成失败'
            }
        })
        // 录音错误
        recorderManager.onError((err) => {
            console.error('录音错误:', err)
            isRecording.value = false
            voiceResult.value = '录音失败，请重试'
        })
    } catch (e) {
        console.error('录音管理器初始化异常:', e)
    }
})

// 开始录音（与 ward 一致：权限校验 + MP3 16k 单声道）
const touchStart = () => {
    uni.getSetting({
        success: (res) => {
            if (!res.authSetting['scope.record']) {
                uni.authorize({
                    scope: 'scope.record',
                    success: () => startRecording(),
                    fail: () => {
                        uni.showToast({ title: '请授权使用麦克风', icon: 'none' })
                    }
                })
            } else {
                startRecording()
            }
        },
        fail: () => startRecording()
    })
}

const startRecording = () => {
    if (!recorderManager) {
        uni.showToast({ title: '录音未初始化', icon: 'none' })
        return
    }
    if (isRecording.value) {
        // 正在录音中，避免重复 start
        return
    }
    // uni.showToast({ title: '正在聆听...', icon: 'none', duration: 60000 })
    try {
        recorderManager.start({
            format: 'mp3',
            sampleRate: 16000,
            numberOfChannels: 1,
            encodeBitRate: 32000
        })
    } catch (e) {
        console.error('启动录音失败:', e)
        uni.showToast({ title: '启动录音失败', icon: 'none' })
    }
}

// 结束录音
const touchEnd = () => {
    if (recorderManager) {
        try { recorderManager.stop() } catch(e) {}
    }
}

// ===== 以下工具函数与 ward 页面保持一致（统一走 uniCloud 云函数：speech-recognition） =====
function detectAudioBase64Type(b64) {
    if (!b64 || b64.length < 4) return 'unknown'
    const head4 = b64.slice(0, 4)
    if (head4 === 'SUQz') return 'mp3'   // ID3 -> MP3
    if (head4 === 'UklG') return 'pcm'   // RIFF/WAV/PCM
    if (head4 === 'GkXf') return 'webm'  // WebM/Matroska
    if (head4 === 'T2dn') return 'ogg'   // Ogg/Opus
    return 'unknown'
}

// 可选：基础工具（供 H5 场景转换使用；与 ward 保持同名实现）
function base64ToUint8Array(b64) {
    const binary = typeof atob !== 'undefined' ? atob(b64) : Buffer.from(b64, 'base64').toString('binary')
    const len = binary.length
    const bytes = new Uint8Array(len)
    for (let i = 0; i < len; i++) bytes[i] = binary.charCodeAt(i)
    return bytes
}
function uint8ToBase64(u8) {
    if (typeof btoa !== 'undefined') {
        let str = ''
        const chunk = 0x8000
        for (let i = 0; i < u8.length; i += chunk) {
            str += String.fromCharCode.apply(null, u8.subarray(i, i + chunk))
        }
        return btoa(str)
    } else {
        return Buffer.from(u8).toString('base64')
    }
}
function downsampleBuffer(buffer, inSampleRate, outSampleRate) {
    if (outSampleRate === inSampleRate) return buffer
    const ratio = inSampleRate / outSampleRate
    const newLen = Math.floor(buffer.length / ratio)
    const result = new Float32Array(newLen)
    let offsetResult = 0
    let offsetBuffer = 0
    while (offsetResult < result.length) {
        const nextOffsetBuffer = Math.round((offsetResult + 1) * ratio)
        let accum = 0, count = 0
        for (let i = offsetBuffer; i < nextOffsetBuffer && i < buffer.length; i++) {
            accum += buffer[i]
            count++
        }
        result[offsetResult] = accum / count
        offsetResult++
        offsetBuffer = nextOffsetBuffer
    }
    return result
}
function floatTo16BitPCM(float32Array) {
    const len = float32Array.length
    const buffer = new ArrayBuffer(len * 2)
    const view = new DataView(buffer)
    let offset = 0
    for (let i = 0; i < len; i++, offset += 2) {
        let s = Math.max(-1, Math.min(1, float32Array[i]))
        view.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true)
    }
    return new Uint8Array(buffer)
}
function buildWavFile(samplesUint8, sampleRate, numChannels) {
    const byteRate = sampleRate * numChannels * 2
    const blockAlign = numChannels * 2
    const dataSize = samplesUint8.length
    const buffer = new ArrayBuffer(44 + dataSize)
    const view = new DataView(buffer)
    writeString(view, 0, 'RIFF')
    view.setUint32(4, 36 + dataSize, true)
    writeString(view, 8, 'WAVE')
    writeString(view, 12, 'fmt ')
    view.setUint32(16, 16, true)
    view.setUint16(20, 1, true)
    view.setUint16(22, numChannels, true)
    view.setUint32(24, sampleRate, true)
    view.setUint32(28, byteRate, true)
    view.setUint16(32, blockAlign, true)
    view.setUint16(34, 16, true)
    writeString(view, 36, 'data')
    view.setUint32(40, dataSize, true)
    const out = new Uint8Array(buffer)
    out.set(samplesUint8, 44)
    return out
}
function writeString(view, offset, str) {
    for (let i = 0; i < str.length; i++) {
        view.setUint8(offset + i, str.charCodeAt(i))
    }
}
async function convertWebmBase64ToPcmWavBase64(b64) {
    if (typeof window === 'undefined') throw new Error('仅 H5 支持 WebAudio 解码')
    const audioCtx = new (window.AudioContext || window.webkitAudioContext)()
    const u8 = base64ToUint8Array(b64)
    const arrayBuf = u8.buffer.slice(u8.byteOffset, u8.byteOffset + u8.byteLength)
    const audioBuffer = await new Promise((resolve, reject) => {
        audioCtx.decodeAudioData(arrayBuf, resolve, reject)
    })
    await audioCtx.close()
    const ch = Math.min(2, audioBuffer.numberOfChannels || 1)
    let mono = new Float32Array(audioBuffer.length)
    if (ch === 1) {
        mono = audioBuffer.getChannelData(0)
    } else {
        const c0 = audioBuffer.getChannelData(0)
        const c1 = audioBuffer.getChannelData(1)
        mono = new Float32Array(audioBuffer.length)
        for (let i = 0; i < audioBuffer.length; i++) mono[i] = (c0[i] + c1[i]) / 2
    }
    const resampled = downsampleBuffer(mono, audioBuffer.sampleRate, 16000)
    const pcm16 = floatTo16BitPCM(resampled)
    const wav = buildWavFile(pcm16, 16000, 1)
    return uint8ToBase64(wav)
}

// 统一上传至云函数（speech-recognition）
const uploadToUniCloud = async (filePath) => {
    uni.getFileSystemManager().readFile({
        filePath,
        encoding: 'base64',
        success: async (res) => {
            let audioBase64 = res.data
            let kind = detectAudioBase64Type(audioBase64)
            // H5 的 webm/ogg 尝试前端转 WAV/PCM16，否则交给云端
            if (kind === 'webm' || kind === 'ogg') {
                const isH5Env = (typeof window !== 'undefined') && (typeof navigator !== 'undefined')
                if (isH5Env) {
                    try {
                        const converted = await convertWebmBase64ToPcmWavBase64(audioBase64)
                        audioBase64 = converted
                        kind = 'pcm'
                        const result = await uniCloud.callFunction({
                            name: 'speech-recognition',
                            data: { audioBase64, audioFormat: 'raw' }
                        })
                        if (result.result.code === 0) {
                            voiceResult.value = result.result.data.text || '识别结果为空'
                        } else {
                            voiceResult.value = `识别失败: ${result.result.message}`
                        }
                        return
                    } catch (e) {
                        console.warn('前端转 WAV 失败，走云端转码:', e)
                    }
                }
                // 非 H5：交云端转码
                try {
                    const result = await uniCloud.callFunction({
                        name: 'speech-recognition',
                        data: { audioBase64, audioFormat: 'webm' }
                    })
                    if (result.result.code === 0) {
                        voiceResult.value = result.result.data.text || '识别结果为空'
                    } else {
                        voiceResult.value = `识别失败: ${result.result.message}`
                    }
                } catch (err) {
                    console.error('云端转码失败:', err)
                    voiceResult.value = '语音识别服务异常，请重试'
                }
                return
            }
            const audioFormat = (kind === 'pcm') ? 'raw' : 'mp3'
            try {
                const result = await uniCloud.callFunction({
                    name: 'speech-recognition',
                    data: { audioBase64, audioFormat }
                })
                if (result.result.code === 0) {
                    voiceResult.value = result.result.data.text || '识别结果为空'
                } else {
                    voiceResult.value = `识别失败: ${result.result.message}`
                }
            } catch (err) {
                console.error('云函数调用失败:', err)
                voiceResult.value = '语音识别服务异常，请重试'
            }
        },
        fail: (err) => {
            console.error('读取音频文件失败:', err)
            voiceResult.value = '音频文件读取失败'
        }
    })
}
			
</script>

<style scoped lang="scss">


.background-container {
	width: 100%;
	height: 305rpx;
	// background-image: url('https://i.postimg.cc/mZpXk7pv/image-png.png');
	background-position: center;
	background-repeat: no-repeat;
	background-size: cover;
	z-index: -1;
	
	.nurse-container{
		position: fixed;
		bottom: 130rpx;
		right: 80rpx;
		width: 100rpx;
		height: 100rpx;
		.nurse_icon{
			width: 100%;
			height: 100%;
		}		
	}
	.man_container{
		position: fixed;
		bottom: 50rpx;
		left: 160rpx;
		width: 100rpx;
		height: 100rpx;
		.man_icon{
			width: 100%;
			height: 100%;
		}
	}
	.next{
		position: fixed;
		right: 30rpx;
		bottom: 120rpx;
	}	
	
	.weighing-scale{
		position: fixed;
		// background-image: url('https://i.postimg.cc/YCTR27LL/image.png');
		left: 20rpx;
		top: 90rpx;
		width: 180rpx;
		height: 150rpx;
		border-radius: 20rpx;
		padding: 0;
		z-index: 6;
		display: flex;
		align-items: flex-end;
		justify-content: center;
		background-size: contain;
		background-repeat: no-repeat;
		background-position: center;
	}
	.people{
		position: fixed;
		top: 100rpx;
		left: 70rpx;
		width: 60rpx;
		height: 120rpx;
		background-color: #2A82E4;
	}
	.voice{
		display: flex;
		position: fixed;
		align-items: center;
		justify-content: center;
		bottom: 40rpx;
		right: 60rpx;
		width: 60rpx;
		height: 60rpx;
		border-radius: 50rpx;
		background-color: #2A82E4;
		.voice-icon{
			position: absolute;	
		}
	}
	.nurse_say{
		position: absolute;
		display: flex;
		align-items: center;
		justify-content: center;
		top: 130rpx;
		right: 160rpx;
		border-radius: 14rpx;
		min-width: 250rpx;
		height: auto;
		padding: 10rpx;
		background-color: #fff;
		white-space: normal;
		word-break: break-all;
		text {
			text-align: center;
			font-size: 18rpx;
		}
	}				
	.man_say{
		position: absolute;
		display: flex;
		align-items: center;
		justify-content: center;
		top: 220rpx;
		left: 260rpx;
		border-radius: 14rpx;
		min-width: 120rpx;
		height: auto;
		padding: 10rpx;
		background-color: #fff;
		white-space: normal;
		word-break: break-all;
		text {
			text-align: center;
			font-size: 18rpx;
		}
	}							
}






</style>